Este proyecto final se propone replicar el ejercicio realizado por Mike Silva, quien analiza el Mercado de Trabajo de los Estados Unidos a partir de la identificación del flujo de trabajadores desde su lugar de residencia (RESIDENCE) hacia su destino de trabajo (WORKPLACE) por medio de la Encuesta de la Comunicad American (ACS) durante el periodo 2006 a 2010. Esta encuesta es tomada del Census Transportation Planning Products (CTTPS) http://ctpp.transportation.org/Pages/5-Year-Data.aspx el cual permite un nivel de desagregación por Estados-Condado. Sin embargo, el proyecto propuesto para el curso replica únicamente dicho flujo hasta el nivel Estados, justificado en la medida que, la solicitud para obtener la base de datos por Estados-Condados está en lista de espera 12 con el número de identificación 6661. Por tal razón, una vez disponga de la información será posible replicar con exactitud los hallazgos del autor. Lo anterior hace que este ejercicio sea interesante pues permite exhibir el aprendizaje derivado del curso. En este sentido, el presente proyecto se desarrolla de la siguiente forma:
Los datos son extraidos en su versión "pura" de la página de CTTP, los cuales contiene el número de trabajadores de acuerdo al flujo de los mismos entre su residencia y lugar de trabajo; una variable llamada "Ouput", la cual recópila la cantidad de trabajadores estimada y con un margen de error. Sin embargo, el autor considera apropiado realizar una serie intervenciones a los datos con el fin de diseñar la red, los cuales los define a partir de los dos indentificadores que se encuentran en la variable Output. Así los procedimientos seguidos son:
Expuesto lo anterior, se da paso al procesamiento de información.
In [26]:
#Importar librerias requeridas para el ejercicio
import pandas as pd
import networkx as nx
from PIL import Image
#Identificación de parámetros
estimate_over_moe_threshold = 0.5
worker_threshold = 100
dont_link_to_self = True
#Leer Base de Datos
df = pd.read_csv('Job_4393.csv', low_memory=False, skiprows=2, thousands=',')
#print (df)
In [2]:
# Cambiar la variable 'Workers 16 and Over' de string a númerico
df['Workers 16 and Over'] = pd.to_numeric(df['Workers 16 and Over'])
# Contando los nodos y los edges del ejercicio
nodes_before = len(pd.DataFrame(pd.concat([df['RESIDENCE'], df['WORKPLACE']])).drop_duplicates())
edges_before = len(df)
print('El número de nodos es' ' ' +str(nodes_before)+ ' ' 'que representan los Estados de USA')
print('El número de edges es' ' ' +str(edges_before)+ ' ' 'que representan al flujo del agente entre su ciudad de residencia y de trabajo')
In [3]:
# Cambiando de formato long (columna) a wide (fila) con el fin de empezar la depuración de los datos
left = df[df['Output']=='Estimate'].drop('Output', 1).rename(columns={'Workers 16 and Over':'Estimate'})
right = df[df['Output']=='Margin of Error'].drop('Output', 1).rename(columns={'Workers 16 and Over':'Margin of Error'})
df = pd.merge(left, right, on=['RESIDENCE','WORKPLACE'])
# Eliminación de datos de acuerdo al criterio 2
df['MOE over EST'] = df['Margin of Error'] / df['Estimate']
df = df[df['MOE over EST'] <= estimate_over_moe_threshold]
# Eliminando columnas Innecesarias, las cuales son las creadas anteriormente
df = df.drop(['Margin of Error', 'MOE over EST'], 1)
# Eliminando datos pequeñas de la base datos (trabajadores por debajo de 100)
df = df[df['Estimate'] >= worker_threshold]
# Eliminando vinculos que se conectan a si mismo
if dont_link_to_self:
df = df[df['RESIDENCE'] != df['WORKPLACE']]
In [4]:
#print (df)
In [5]:
# Creando los nodos para exportar a Gephi
nodes = pd.DataFrame(pd.concat([df['RESIDENCE'], df['WORKPLACE']])).drop_duplicates().rename(columns={0:'County'})
nodes= nodes.reset_index(drop=True)
nodes['Id'] = nodes.index
In [6]:
# Anexando los codigos de los condados FIPS a los nodos
fips = pd.read_csv('fips.csv', low_memory=False, converters={'FIPS': str})
nodes = pd.merge(nodes, fips)
#print (nodes)
#print (df)
In [7]:
# Ahora se adiciona la columna Source
df = pd.merge(df, nodes, left_on='RESIDENCE', right_on='County')
df = df.drop(['County', 'FIPS'], 1).rename(columns={'Id':'Source'})
# Ahora se adiciona la columna Target
df = pd.merge(df, nodes, left_on='WORKPLACE', right_on='County')
df = df.drop(['County','FIPS'], 1).rename(columns={'Id':'Target'})
# Contando los nodes y los edges
nodes_after = len(nodes)
edges_after = len(df)
#print (df)
In [10]:
# Calculo de los nodos iniciales y finales despues de realizar la depuración de datos con el fin de evaluar la pérdida de información
nodes_percent = nodes_after * 100 / nodes_before
edges_percent = edges_after * 100 / edges_before
print('Tenemos ahora' ' ' +str(nodes_after)+' de los '+str(nodes_before)+' nodes con que se inició el ejercicio. Estó da una tasa de -> ('+str(nodes_percent)+'%)')
print('Tenemos ahora' ' ' +str(edges_after)+' de los '+str(edges_before)+' edges con que se inició el ejercicio. Estó da una tasa de -> ('+str(edges_percent)+'%)')
In [12]:
# Creamos el Grafo en python para posteriormnte importarlo a Gephi (Este será Dirigido)
G = nx.DiGraph()
# Add in the edges
for row in df.iterrows():
G.add_edge(row[1][3], row[1][4], weight=row[1][2])
#print(G.edges())
In [13]:
#print (nodes)
In [15]:
# Etiquetas para los nodos
labels = nodes[['Id','County']].to_dict()
labels = labels['County']
fips = nodes[['Id','FIPS']].to_dict()
fips = fips['FIPS']
nx.set_node_attributes(G, 'label', labels)
nx.set_node_attributes(G, 'fips', fips)
In [17]:
# Exportar el grafo de construido en Python a formato graphml y el listado de edges
nx.write_graphml(G,'U.S.A Labor Market.graphml')
# Pequeña validación de que el nodo tiene asociado su respectiva etiqueta (Label)
G.node[16]['label']
Out[17]:
Una vez finaliza el diseño del grafo en python, se procede a importarlo a Gephi y emprender la identificación de las comunidades. En ese sentido, el software arroja la existencia de siete (7) communities, las cuales fueron establecidas de acuerdo al peso (weight) del vinculo, recordando que este es el número de trabajadores. Así, los procedimientos seguidos en Gephi fueron los siguientes:
De esta forma, el grafo que se presenta a continuación permite visualizar los Communities, que combinado con el comando "Counter" se reporta la cantidad de nodos que conforman cada uno de los Communities; luego entonces, hace apropiado concluir de manera preliminar que existen 2 comunidades que concentran la mayor cantidad de trabajadores, siendo estas la número 4, 5 y 0 en orden descendente.
In [1]:
from PIL import Image
img = Image.open('USA Labor Market.png')
img.show()
In [23]:
# Read in the Gephi output
Gephi = pd.read_csv('U.S. Labor Market [Nodes].csv', low_memory=False, converters={'fips': str})
Gephi = Gephi[['fips','Modularity Class']]
#print(Gephi)
In [24]:
# Cambiar la variable 'Workers 16 and Over' de string a númerico
Gephi['Modularity Class'] = pd.to_numeric(Gephi['Modularity Class'])
Communities=pd.Series(Gephi['Modularity Class'])
In [25]:
from collections import Counter
Counter(Communities)
Out[25]:
(1) Este ejercicio de replicar el flujo de trabajadores de los Estados Unidos desde su lugar de residencia hasta su lugar de trabajo es particularmente interesante por cuanto puede ser interpretado como un esfuerzo por detectar la demanda de trabajo que hacen los Estados; una vez es detectado las Communities claro está. En este sentido, se reconoce que el tamaño de la red no es muy grande (51 nodos), donde cada nodo tiene un grado promedio de apróximadamente 21, con la particularidad de que es una red dirigida y al calcular el Average Clustering Coefficient se obtiene un valor de 0.715 se puede concluir que hay una alta interconexión entre los nodos y el vecindario.
(2) La detección de los siete (7) Communities del ejercicio evidenció que existen 3 de ellos que, de acuerdo al peso del vinculo, hace posible aseverar que concentrar una mayor población trabajando, y por ende son las que demandan más manos de obra; mientras que existe uno que tiene una menor cantidad de Estados en comparación con el resto de Communities. En ese sentido, estas comunidades junto con sus estados son:
(3) Se espera replicar el ejercicio por completo una vez se cuente con la base de datos Estados-Condados; pues el autor identificó que existen 3040 nodos y 15309 edge, arrojando un total de 70 Communities; lo cual hace muy interesante observar cuales serían los condados que demandan mayor mano de obra, determinado por el número de trabajadores que conforman el peso de la red.
(1) En principio, consideraba trabajar una red dinámica con la base de datos de CONFAMA pero ciertamente no logré darle la trasncición temporal al software Gephi y ante la restricción de tiempo, opté por seguir trabajando el ejercicio de Mieke; el cual condujo a que elevera sustancialmente mi curva de aprendizaje en Python. De igual forma, la manera en como se encontraba la base de datos no me hacia posible brindar una interpretación economica, dado que, las metricas estudiadas no se ajustan del todo bien, cuando estas son calculadas para redes bipartitas; según logré consultar en documentos publicados en la red.
(2) El mayor resto es ubicar el grafo en un mapa, el cual observé que este autor hizo por medio de la libreria "Basemap" pero por más que me documenté sobre ella no logré introducirla. Por tal razón, estaría agradecido si puede brindarme orientación sobre ello.
(3) Como transmití en númerosas ocasiones, este curso es mi primer paso para diseñar la estructura del segundo capítulo de mi tesis doctoral; el cual considero que, a estas alturas, cuento con las herramientas análiticas para realizarlo. Lo anterior se justifica que si bien quisiera replicar este ejercicio para Colombia si sería posible, pues al examinar la Gran Encuesta Integrada de hogares 2016 observé que la pregunta P388 identifica conclaridad el departamento donde el agente realiza el trabajo principalmente, mientras que en el modulo vivienda, cuento con información sobre el area metropolitana de Residencia. Si bien no son el mismo agente economico en el tiempo, puedo realizar el analisis como el replicado, ya que se si puedo obtener el número de trabajadores por Departamento. El resto será diseñar con calma esto.
**Terminado a las 2:32am del 29 de Mayo de 2017**